package service

import (
	"errors"
	"fmt"
	"github.com/go-xorm/xorm"
	"github.com/wonderivan/logger"
	"strconv"
	"ucenter/app/dao"
	"ucenter/app/model"
)

var balanceService *BalanceService

type BalanceService struct{}

func GetBalanceService() *BalanceService {
	if balanceService == nil {
		balanceService = new(BalanceService)
	}
	return balanceService
}

func (bs *BalanceService) InitBalance(uBalance *model.UserBalance) {
	_, err := dao.GetMysql().Insert(uBalance)
	if err != nil {
		logger.Error("BalanceService_InitBalance_GetBalance | err=%v | data=%+v", err, uBalance)
	}
}

/**
 * 统一用户余额操作
 * param: *model.BalanceRequest bl
 * return: string
 * return: []map[string]string
 */
func (bs *BalanceService) OperateBalance(bl *model.BalanceRequest, rawData string) (data []*model.UserBalance, err error) {
	//请求日志 todo
	bReq := new(model.UserBalanceRequest)
	bReq.Op = bl.Op
	bReq.FromId = 1 //游戏服
	bReq.CashNum = fmt.Sprint(bl.CashNum)
	bReq.RoomType = bl.RoomType
	bReq.RoomId = bl.RoomId
	bReq.Data = rawData
	_, err = dao.GetMysql().Insert(bReq)
	if err != nil {
		return
	}
	switch bl.RoomType {
	case 1, 5:
		//points算法
		data, err = bs.BalancePoints(bl)
	case 2, 3, 4, 6, 7, 8:
		//普通算法
		bl.CashNumInt64 = int64(bl.CashNum)
		data, err = bs.BalanceNormal(bl)
	}
	return
}

/**
 * 普通结算算法
 * param: *model.BalanceRequest bl
 * return: string
 */
func (bs *BalanceService) BalanceNormal(bl *model.BalanceRequest) (data []*model.UserBalance, err error) {
	_, err = dao.GetMysql().Transaction(func(session *xorm.Session) (i interface{}, err error) {
		//插入流水更新余额
		if bl.Op == model.Op_Dim || bl.Op == model.Op_Plus {
			for _, v := range bl.UidS {
				//校验当前用户uid余额是否充足
				var userBalance = new(model.UserBalance)
				exist, err := session.Where("uid=?", v).ForUpdate().Get(userBalance)
				if err != nil {
					logger.Error("BalanceService_BalanceNormal_GetBalance | err=%v | uid=%v", err, v)
					err = errors.New("DB_ERROR")
					return nil, err
				}
				if model.RoomTypeGameType[bl.RoomType] == "cash" {
					if bl.Op == model.Op_Dim {
						userBalance.Cash -= bl.CashNumInt64
					} else {
						userBalance.Cash += bl.CashNumInt64
					}
				} else {
					if bl.Op == model.Op_Dim {
						userBalance.Score -= bl.CashNumInt64
					} else {
						userBalance.Score += bl.CashNumInt64
					}
				}
				if !exist || userBalance.Score < 0 || userBalance.Cash < 0 {
					err = errors.New(fmt.Sprintf("UserBalance_Insufficient_Uid_%v", v))
					return nil, err
				}
				if userBalance.Score < 0 {
					err = errors.New(fmt.Sprintf("UserScore_Insufficient_Uid_%v", v))
					return nil, err
				}
				if userBalance.Cash < 0 {
					err = errors.New(fmt.Sprintf("UserCash_Insufficient_Uid_%v", v))
					return nil, err
				}
				_, err = session.Where("uid=?", v).Update(userBalance)
				if err != nil {
					logger.Error("BalanceService_BalanceNormal_UpdateError | err=%v", err)
					err = errors.New("DB_UPDATE_ERROR")
					return nil, err
				}
				//插入操作流水日志
				balanceLog := new(model.UserBalanceLog)
				balanceLog.FromId = 1
				balanceLog.Uid = v
				balanceLog.RoomId = bl.RoomId
				balanceLog.RoomType = bl.RoomType
				balanceLog.Op = bl.Op
				balanceLog.Value = bl.CashNumInt64
				_, err = session.Insert(balanceLog)
				if err != nil {
					logger.Error("BalanceService_BalanceNormal_Log_DBError | err=%v", err)
					err = errors.New("DB_INSERT_LOG_ERROR")
					return nil, err
				}
				//此处可维护一个缓存  todo
				data = append(data, userBalance)
			}
		} else if bl.Op == model.Op_Tied {
			//平局结算
			lCount := len(bl.LoseUidS)
			var losePrize int64 //有输家的总奖金
			if lCount > 0 {
				losePrize = int64(lCount) * bl.CashNumInt64
			}
			wCount := len(bl.UidS)
			for _, v := range bl.UidS {
				var userBalance = new(model.UserBalance)
				exist, err := session.Where("uid=?", v).ForUpdate().Get(userBalance)
				if err != nil {
					logger.Error("BalanceService_BalanceNormal_GetBalance_3 | err=%v | uid=%v", err, v)
					err = errors.New("DB_ERROR")
					return nil, err
				}
				if !exist {
					err = errors.New(fmt.Sprintf("UserBalance_NotExist_Uid_%v", v))
					return nil, err
				}
				personalPrize := bl.CashNumInt64 //总奖金 把门票加上
				if losePrize > 0 {
					personalPrize += losePrize / int64(wCount) //从输钱的人赢的奖金，赢钱的人平分
				}
				finalPrize := int64(float64(personalPrize) * model.Fee) //扣个费

				if model.RoomTypeGameType[bl.RoomType] == "cash" {
					userBalance.Cash += finalPrize
				} else {
					userBalance.Score += finalPrize
				}
				_, err = session.Where("uid=?", v).Update(userBalance)
				if err != nil {
					logger.Error("BalanceService_BalanceNormal_UpdateError_3 | err=%v", err)
					err = errors.New("DB_UPDATE_ERROR")
					return nil, err
				}
				//插入操作流水日志
				balanceLog := new(model.UserBalanceLog)
				balanceLog.FromId = 1
				balanceLog.Uid = v
				balanceLog.RoomId = bl.RoomId
				balanceLog.RoomType = bl.RoomType
				balanceLog.Op = bl.Op
				balanceLog.Value = finalPrize
				balanceLog.Fee = personalPrize - finalPrize
				_, err = session.Insert(balanceLog)
				if err != nil {
					logger.Error("BalanceService_BalanceNormal_Log_DBError_3 | err=%v", err)
					err = errors.New("DB_INSERT_LOG_ERROR")
					return nil, err
				}
				//此处可维护一个缓存  todo
				data = append(data, userBalance)
			}
		} else {
			//结算逻辑 - 可能废弃
			var userBalance = new(model.UserBalance)
			_, err := session.Where("uid=?", bl.Wins).ForUpdate().Get(userBalance)
			if err != nil {
				logger.Error("BalanceService_BalanceNormal_GetBalance_2 | err=%v | uid=%v", err, bl.Wins)
				err = errors.New("DB_ERROR")
				return nil, err
			}
			winsPrize := int64(len(bl.UidS)) * bl.CashNumInt64
			finalPrize := int64(float64(winsPrize) * model.Fee) //扣除费用奖金
			if model.RoomTypeGameType[bl.RoomType] == "cash" {
				userBalance.Cash += finalPrize
			} else {
				userBalance.Score += finalPrize
			}
			_, err = session.Where("uid=?", bl.Wins).Update(userBalance)
			if err != nil {
				logger.Error("BalanceService_BalanceNormal_UpdateError_2 | err=%v", err)
				err = errors.New("DB_UPDATE_ERROR")
				return nil, err
			}
			//插入操作流水日志
			balanceLog := new(model.UserBalanceLog)
			balanceLog.FromId = 1
			balanceLog.Uid = bl.Wins
			balanceLog.RoomId = bl.RoomId
			balanceLog.RoomType = bl.RoomType
			balanceLog.Op = bl.Op
			balanceLog.Value = finalPrize
			balanceLog.Fee = winsPrize - finalPrize
			_, err = session.Insert(balanceLog)
			if err != nil {
				logger.Error("BalanceService_BalanceNormal_Log_DBError_2 | err=%v", err)
				err = errors.New("DB_INSERT_LOG_ERROR")
				return nil, err
			}
			//此处可维护一个缓存  todo
			data = append(data, userBalance)
		}
		return
	})
	return
}

/**
 * points计算分
 * param: *model.BalanceRequest bl
 * return: string
 */
func (bs *BalanceService) BalancePoints(bl *model.BalanceRequest) (data []*model.UserBalance, err error) {
	_, err = dao.GetMysql().Transaction(func(session *xorm.Session) (i interface{}, err error) {
		//插入流水更新余额
		if bl.Op == model.Op_Dim || bl.Op == model.Op_Plus {
			for _, v := range bl.UidS {
				//校验用户余额是否充足
				var userBalance = new(model.UserBalance)
				exist, err := session.Where("uid=?", v).ForUpdate().Get(userBalance)
				if err != nil {
					logger.Error("BalanceService_BalancePoints_GetBalance | err=%v | uid=%v", err, v)
					err = errors.New("DB_ERROR")
					return nil, err
				}
				finalNum := int64(bl.CashNum * model.PointsMax)
				if model.RoomTypeGameType[bl.RoomType] == "cash" {
					if bl.Op == model.Op_Dim {
						userBalance.Cash -= finalNum //此处 乘以PointsMax
					} else {
						userBalance.Cash += finalNum
					}
				} else {
					if bl.Op == model.Op_Dim {
						userBalance.Score -= finalNum
					} else {
						userBalance.Score += finalNum
					}
				}
				if !exist {
					err = errors.New(fmt.Sprintf("UserBalance_Insufficient_Uid_%v", v))
					return nil, err
				}
				if userBalance.Score < 0 {
					err = errors.New(fmt.Sprintf("UserScore_Insufficient_Uid_%v", v))
					return nil, err
				}
				if userBalance.Cash < 0 {
					err = errors.New(fmt.Sprintf("UserCash_Insufficient_Uid_%v", v))
					return nil, err
				}
				_, err = session.Where("uid=?", v).Update(userBalance)
				if err != nil {
					logger.Error("BalanceService_BalancePoints_UpdateError | err=%v", err)
					err = errors.New("DB_UPDATE_ERROR")
					return nil, err
				}
				//插入操作流水日志
				balanceLog := new(model.UserBalanceLog)
				balanceLog.FromId = 1
				balanceLog.Uid = v
				balanceLog.RoomId = bl.RoomId
				balanceLog.RoomType = bl.RoomType
				balanceLog.Op = bl.Op
				balanceLog.Value = finalNum
				_, err = session.Insert(balanceLog)
				if err != nil {
					logger.Error("BalanceService_BalancePoints_Log_DBError | err=%v", err)
					err = errors.New("DB_INSERT_LOG_ERROR")
					return nil, err
				}
				//此处可维护一个缓存  todo
				data = append(data, userBalance)
			}
		} else if bl.Op == model.Op_Settle {
			//结算逻辑
			entryFee := int64(bl.CashNum * model.PointsMax) //入场费
			totalPrize := entryFee                          //总奖金
			//lose
			for _, v := range bl.LoseUidS {
				var userBalance = new(model.UserBalance)
				_, err := session.Where("uid=?", v.Uid).ForUpdate().Get(userBalance)
				if err != nil {
					logger.Error("BalanceService_BalancePoints_Lose_GetBalance | err=%v | uid=%v", err, v)
					err = errors.New("DB_ERROR")
					return nil, err
				}
				//归还输钱奖金
				sup := int64(v.Score * bl.CashNum)
				if model.RoomTypeGameType[bl.RoomType] == "cash" {
					userBalance.Cash += sup
				} else {
					userBalance.Score += sup
				}
				losePrize := entryFee - sup                         //输的总数
				finalPrize := int64(float64(losePrize) * model.Fee) //赢的人获得奖金-扣费
				totalPrize += finalPrize                            //累加

				_, err = session.Where("uid=?", v.Uid).Update(userBalance)
				if err != nil {
					logger.Error("BalanceService_BalancePoints_Lose_UpdateError | err=%v", err)
					err = errors.New("DB_UPDATE_ERROR")
					return nil, err
				}
				//插入操作流水日志
				balanceLog := new(model.UserBalanceLog)
				balanceLog.FromId = 1
				balanceLog.Uid = v.Uid
				balanceLog.RoomId = bl.RoomId
				balanceLog.RoomType = bl.RoomType
				balanceLog.Op = bl.Op
				balanceLog.Desc = "lose"
				balanceLog.Value = sup
				balanceLog.LosePrize = losePrize
				balanceLog.Fee = losePrize - finalPrize
				_, err = session.Insert(balanceLog)
				if err != nil {
					logger.Error("BalanceService_BalancePoints_Log_Lose_DBError | err=%v", err)
					err = errors.New("DB_INSERT_LOG_ERROR")
					return nil, err
				}
				//此处可维护一个缓存  todo
				data = append(data, userBalance)
			}
			//wins
			var userBalance = new(model.UserBalance)
			_, err := session.Where("uid=?", bl.Wins).ForUpdate().Get(userBalance)
			if err != nil {
				logger.Error("BalanceService_BalancePoints_Win_GetBalance | err=%v | uid=%v", err, bl.Wins)
				err = errors.New("DB_ERROR")
				return nil, err
			}
			if model.RoomTypeGameType[bl.RoomType] == "cash" {
				userBalance.Cash += totalPrize
			} else {
				userBalance.Score += totalPrize
			}
			_, err = session.Where("uid=?", bl.Wins).Update(userBalance)
			if err != nil {
				logger.Error("BalanceService_BalancePoints_Win_UpdateError | err=%v", err)
				err = errors.New("DB_UPDATE_ERROR")
				return nil, err
			}
			//插入操作流水日志
			balanceLog := new(model.UserBalanceLog)
			balanceLog.FromId = 1
			balanceLog.Uid = bl.Wins
			balanceLog.RoomId = bl.RoomId
			balanceLog.RoomType = bl.RoomType
			balanceLog.Op = bl.Op
			balanceLog.Desc = "win"
			balanceLog.Value = totalPrize
			_, err = session.Insert(balanceLog)
			if err != nil {
				logger.Error("BalanceService_BalancePoints_Log_Win_DBError | err=%v", err)
				err = errors.New("DB_INSERT_LOG_ERROR")
				return nil, err
			}
			data = append(data, userBalance)
		}
		return
	})
	return
}

/**
 * 批量获取用户余额
 * param: []int64 uids
 * return: []*model.UserBalance
 */
func (bs *BalanceService) GetBalance(req *model.GetUserBalance) (data []model.UserBalance, err error) {
	//次数可优先取缓存 todo
	uids := []string{}
	for _, u := range req.Uid {
		uids = append(uids, strconv.FormatInt(u, 10))
	}
	session := dao.GetMysql().In("uid", req.Uid[:])
	err = session.Find(&data)
	if err != nil {
		logger.Error("BalanceService_GetBalance_Error | err=%v | req=%+v", err, req)
		return
	}
	return
}
